home *** CD-ROM | disk | FTP | other *** search
/ No Fragments Archive 12: Textmags & Docs / nf_archive_12.iso / MAGS / SOURCES / ATARI_SRC.ZIP / atari source / HDX_BACK / HDX500 / ACSI.S < prev    next >
Encoding:
Text File  |  2001-02-09  |  14.6 KB  |  532 lines

  1. ;+
  2. ; Edit History
  3. ;
  4. ; May-22-89    ml.    Started this with AHDI 3.00.
  5. ; Aug-21-89    ml.    Added format code.  It's seperated because it waits
  6. ;            forever for command completion.
  7. ; Sep-08-89    ml.    Added a 1 microsec delay (rstdelay()) after each 
  8. ;            access to the DMA chip which may reset the chip.
  9. ; Sep-13-89    ml.    If need to execute a command more than once to
  10. ;            get all bytes into RAM, use the original allocation
  11. ;            length for subsequent calls.
  12. ; Oct-06-89    ml.    Added start/stop unit code.  It's seperated because
  13. ;            it needs longer timeouts.
  14. ; Nov-08-89    ml.    Added a delay in _rcvacsi() when looping to do more
  15. ;            than one _sblkacsi().
  16. ; Nov-27-89    ml.    Added .even after declaring control.
  17. ; Dec-05-89    ml.    Flushing of D cache before reading status byte.
  18. ; Apr-09-90    ml.    Added a "read" from WDL to actually "set" the bit
  19. ;            for the new MMU chip.  It's a bug in the chip.  
  20. ;            Temporary only.
  21. ; Apr-20-90    ml.    Made the "read" added on Apr-09-90 conditional
  22. ;            assembly.  RDWDL flag defined in defs.h.
  23. ; Sep-24-91    ml.    Added the _slwacsi flag to indicate whether we
  24. ;            are talking to a slow ACSI device.  If so, extra
  25. ;            delay is necessary to wait for the device to
  26. ;            response.
  27. ; Oct-07-91    ml.    Instead of using "lsr" to check if transfer is
  28. ;            a multiple of 16 in _rcvacsi(), use "andi".
  29. ; Dec-03-91    ml.    BIG OOPS: at qd0, the label 'sdelay' was wrong so
  30. ;            that the add of _hz_200 to d0 was INSIDE the loop!
  31. ;            (just like in dmaread.s)  It is now fixed.
  32. ;-
  33.  
  34.  
  35. .include    "defs.h"
  36. .include    "sysvar.h"
  37. .include    "68030.s"
  38.  
  39.  
  40. ;+
  41. ;  Hardware definitions for ACSI
  42. ;-
  43. WDC        equ    $ffff8604
  44. WDL        equ    $ffff8606
  45. WDCWDL        equ    WDC        ; used for long writes
  46. XWDL        equ    WDL-WDC        ; offset from wdc to wdl
  47.  
  48. DMAHI        equ    $ffff8609
  49. DMAMID        equ    DMAHI+2
  50. DMALOW        equ    DMAMID+2
  51. GPIP        equ    $fffffa01
  52.  
  53.  
  54. ;+
  55. ;  Tunable (delay) values for ACSI
  56. ;-
  57. ACLTMOUT    equ    600        ; long-timeout (3 S)
  58. ACSTMOUT    equ    20        ; short-timeout (100 mS)
  59. SLWACLTO    equ    5000        ; long-timeout (25 S) for slow ACSI
  60. SLWACSTO    equ    42        ; short-timeout (205 mS) for slow ACSI
  61.  
  62.  
  63. ;+
  64. ; Declarations
  65. ;-
  66. lastacstm:    dc.l    0        ; controller last accessed time
  67. control:    dc.b    0        ; flag for sending control byte
  68.         .globl    _slwacsi
  69. _slwacsi:    dc.b    0        ; assume not doing slow ACSI
  70. .even
  71.  
  72. .extern        _cmdblk
  73.  
  74.  
  75. ;+
  76. ; LONG _qdone() - Wait for command byte handshake
  77. ; LONG _fdone() - Wait for operation complete
  78. ; Passed:    nothing
  79. ;
  80. ; Returns:    EQ: no timeout
  81. ;        MI: timeout condition
  82. ;
  83. ; Uses:        D0
  84. ;
  85. ;-
  86.  
  87. .if    !DRIVER
  88. _slwfdone:                ; fdone for slow response
  89.     move.l    #SLWACLTO,d0
  90.     bra.s    qd0
  91. .endif
  92.  
  93. _fdone:    move.l    #ACLTMOUT,d0
  94.     bra.s    qd0
  95.  
  96. .if    !DRIVER
  97. _slwqdone:                ; qdone for slow response
  98.     moveq    #SLWACSTO,d0    
  99.     bra.s    qd0
  100. .endif
  101.  
  102. _qdone:    moveq    #ACSTMOUT,d0
  103.  
  104. qd0:    tst.b    _slwacsi        ; talking to slow ACSI device?
  105.     beq.s    qd1            ; if not, go wait for interrupt
  106.                     ; else
  107.     move.l    d0,-(sp)        ; save timeout value
  108.     moveq    #2,d0            ; busy-wait delay for slow ACSI
  109.     add.l    _hz_200,d0        ; minimum 20 microsec.
  110. sdelay:    cmp.l    _hz_200,d0
  111.     bge.s    sdelay
  112.     move.l    (sp)+,d0        ; restore timeout value
  113.  
  114. qd1:    add.l    _hz_200,d0
  115. qd2:    cmp.l    _hz_200,d0        ; timeout?
  116.     bcs.s    qdq            ; (i give up, return NE)
  117.     btst    #5,GPIP            ; interrupt?
  118.     bne.s    qd2            ; (not yet)
  119.  
  120.     moveq    #0,d0            ; return EQ (no timeout)
  121.     rts
  122.  
  123. qdq:    moveq    #-1,d0
  124.     rts
  125.  
  126.  
  127. ;+
  128. ; Wait for end of SASI command
  129. ;
  130. ; Passed:    d1 value to be written to wdl
  131. ;
  132. ; Returns:    EQ: success (error code in D0.W)
  133. ;        MI: timeout (-1 in D0.W)
  134. ;        NE: failure (SASI error code in D0.W)
  135. ;
  136. ; Uses:        d0
  137. ;
  138. ; Comments: (12/05/89)
  139. ;    The flushing of D cache is necessary per Jim Tittsler.  For
  140. ; detail, refer to mail sent by jwt on 12/04/89 about ACSI DMA.
  141. ;-
  142. .if    !DRIVER
  143.     .globl    _cachexst
  144. _cachexst:    dc.b    0
  145.  
  146. _slwendcmd:
  147.     bsr    _slwfdone        ; wait for operation complete
  148.     bra.s    end0
  149. .else
  150.     .extern    _cachexst
  151. .endif
  152.  
  153. _endcmd:
  154.     bsr    _fdone            ; wait for operation complete
  155. end0:    bmi.s    endce            ; (timed-out, so complain)
  156.  
  157. cmdcmp:    tst.b    _cachexst        ; '030 cache exists
  158.     beq.s    end1            ; if not, fine
  159.                     ; else, dump D cache
  160.     move.w    sr,-(sp)        ; go to IPL 7
  161.     ori.w    #$700,sr        ; no interrupts right now kudasai
  162.     movecacrd0            ; d0 = (cache control register)
  163.     ori.w    #$800,d0        ; dump the D cache
  164.     moved0cacr            ; update cache control register
  165.     move.w    (sp)+,sr        ; restore interrupt state
  166.  
  167. end1:    move.w    d1,WDL
  168.     move.w    WDC,d0            ; get the result
  169.     and.w    #$00ff,d0        ; (clean it up), if non-zero should
  170.                     ; do a ReadSense command to learn more
  171. endce:    move.l    _hz_200,lastacstm    ; update controller last accessed time
  172.     addq.l    #2,lastacstm        ; lastacstm = _hz_200 + 2;
  173.     rts                
  174.  
  175.  
  176. ;+
  177. ;  Unlock DMA chip and return completion status;
  178. ;-
  179. _hdone:    move.w    #$80,WDL    ; Landon's code seems to presume we put 
  180.                 ;  $80 there
  181.     clr    flock        ; NOW, signal that we are done
  182.     rts
  183.  
  184.  
  185. ;+
  186. ; delay()
  187. ;    5 - 10ms kludge delay for message byte sent back by controller.
  188. ;-
  189. _delay:    move.l    d0,-(sp)        ; preserve d0
  190.     move.l    lastacstm,d0        ; d0 = controller last accessed time
  191. wait:    cmp.l    _hz_200,d0        ; while (_hz_200 <= lastacstm)
  192.     bcc.s    wait            ;    wait()
  193.     move.l    (sp)+,d0        ; restore d0
  194.     rts
  195.  
  196.  
  197. ;+
  198. ; smplacsi() - send a simple ACSI command (ie. no DMA involved)
  199. ;
  200. ;    d0.w = physical unit number
  201. ;    d1.l = transfer length (in bytes)
  202. ;    d2.w = command length (NCMD or LCMD)
  203. ;    a0.l = buffer address
  204. ;-
  205.     .globl    _smplacsi
  206. _smplacsi:
  207.     st    flock            ; lock FIFO
  208.     bsr    _delay            ; delay if necessary
  209.     movea.l    #WDC,a1            ; a1 = pointer to DMA chip
  210.     andi.w    #7,d0            ; mask off the flags to get unit num
  211.     moveq    #0,d1            ; no DMA
  212.     bsr    sblkacsi        ; send command block
  213.     bra    _hdone            ; cleanup after IRQ
  214.  
  215.  
  216. ;+
  217. ; rcvacsi() - send a ACSI command which receives data back.
  218. ;
  219. ; Passed:
  220. ;    d0.w = physical unit number
  221. ;    d1.l = transfer length (in bytes)
  222. ;    d2.w = command length (NCMD or LCMD)
  223. ;    a0.l = buffer address
  224. ;
  225. ; Comments:
  226. ;    This routine assumes that if you are transferring more than 512
  227. ; bytes, the transfer length must be a multiple of 16 bytes.  It also 
  228. ; assumes the allocation length byte is always at byte 4 in the command
  229. ; block. (Therefore, it won't work with Receive Diagnostic ($1c) if data
  230. ; length is not a multiple of 16 bytes.  But Receive Diagnostic has never
  231. ; been used.)
  232. ;    The transfer length in register D1 MUST be greater than 0.
  233. ;-
  234.     .globl    _rcvacsi
  235. _rcvacsi:
  236.     st    flock            ; lock FIFO
  237.     move.w    d3,-(sp)        ; preserve d3
  238.     bsr    _delay            ; delay if necessary
  239.     movea.l    #WDC,a1            ; a1 = pointer to DMA chip
  240.  
  241.     bsr    setadma            ; set DMA pointer
  242.     move.w    #$190,XWDL(a1)    ;WDL    ; toggle DMA chip for "receive"
  243.     bsr    rstdelay        ; delay
  244.     move.w    #$090,XWDL(a1)    ;WDL
  245.     bsr    rstdelay        ; delay
  246.  
  247. .if    RDWDL
  248.     tst.w    XWDL(a1)        ; to point MMU to correct direction
  249. .endif    ;RDWDL
  250.  
  251.     bsr    setacnt            ; set DMA count
  252.  
  253.     andi.w    #7,d0            ; mask off the flags to get unit num
  254.                     ; find # times need to send it
  255.     cmpi.l    #512,d1            ; transferring < 512 bytes?
  256.     bcs.s    .0            ; if so, go find # times to send
  257.     moveq    #0,d1            ; else assume it's 16*n, send once
  258.     bra.s    .4
  259.  
  260. .0:    move.w    d1,d3            ; d3 = transfer length
  261.     cmpi.w    #16,d1            ; transferring < 16 bytes?
  262.     bcs.s    .1            ; if so, find # times to make 16 bytes
  263.  
  264.     andi.w    #$0f,d1            ; else, is it multiple of 16 bytes?
  265.     beq.s    .4            ; if so, just do once (d1.w = 0)
  266.     moveq    #1,d1            ; else, need to do twice
  267.     bra.s    .4
  268.  
  269. .1:    moveq    #16,d1            ; find # times to make 16 bytes
  270.     divu    d3,d1            ; d1.w = 16 / transfer length
  271.     subq.w    #1,d1            ; dbra likes one less
  272.  
  273. .2:    swap    d1            ; d1.w = remainder
  274.     tst.w    d1            ; any remainder?
  275.     bne.s    .3            ; if yes, go add one to the quotient
  276.     swap    d1            ; if no, # times to send = quotient
  277.     bra.s    .4
  278.  
  279. .3:    swap    d1            ; d1.w    = # times to send command
  280.     addq.w    #1,d1            ;    = quotient + 1
  281.  
  282. .4:    lea    _cmdblk,a0        ; a0 = address of command block
  283. .5:    movem.l    d0-d2/a0,-(sp)        ; save d0 through d2 and a0
  284.     moveq    #0,d1            ; direction of DMA is IN
  285.     bsr    _delay            ; delay if necessary
  286.     bsr    sblkacsi        ; send the command block
  287.     tst.w    d0            ; successful?
  288.     bne.s    .7            ; if not, quit
  289.     movem.l    (sp)+,d0-d2/a0        ; else restore d0 through d2 and a0
  290.     dbra    d1,.6            ; done yet?
  291.     moveq    #0,d0            ; command block sent successfully
  292.     bra.s    raend            ; phone home...
  293.  
  294. .6:    moveq    #-1,d0            ; unit number already in command block
  295.     move.b    d3,4(a0)        ; modify transfer length
  296.     bra.s    .5            ; send it enough times
  297.  
  298. .7:    adda    #16,sp            ; cleanup stack
  299. raend:    move.w    (sp)+,d3        ; restore d3
  300.     bra    _hdone            ; cleanup after IRQ
  301.  
  302.  
  303. ;+
  304. ; wrtacsi() - send an ACSI command which will write data to the target
  305. ;
  306. ; Passed:
  307. ;    d0.w = physical unit number
  308. ;    d1.l = transfer length (in bytes)
  309. ;    d2.w = command length (NCMD or LCMD)
  310. ;    a0.l = buffer address
  311. ;-
  312.     .globl    _wrtacsi
  313. _wrtacsi:
  314.     st    flock            ; lock FIFO
  315.     bsr    _delay
  316.     movea.l    #WDC,a1            ; a1 = pointer to DMA chip
  317.  
  318.     bsr    setadma            ; set DMA pointer
  319.     move.w    #$90,XWDL(a1)    ;WDL    ; toggle DMA chip for "send"
  320.     bsr    rstdelay        ; delay 
  321.     move.w    #$190,XWDL(a1)    ;WDL
  322.     bsr    rstdelay        ; delay
  323.  
  324. .if    RDWDL
  325.     tst.w    XWDL(a1)        ; to point MMU to correct direction
  326. .endif    ;RDWDL
  327.  
  328.     bsr    setacnt            ; set DMA count
  329.     
  330.     andi.w    #7,d0            ; mask off the flags to get unit num
  331.     move.l    #$0100,d1        ; d1 = direction of DMA is OUT
  332.     bsr    sblkacsi        ; send the command block
  333.  
  334. waend:    bra    _hdone            ; cleanup after IRQ
  335.  
  336.  
  337. ;+
  338. ; sblkacsi() - set DMA pointer and count and send command block
  339. ;
  340. ; Passed:
  341. ;    d0.w = physical unit number
  342. ;    d1.l = direction of DMA ($0000 for IN or $0100 for OUT)
  343. ;    d2.w = command length (NCMD or LCMD)
  344. ;    a1.l = pointer to DMA chip
  345. ;
  346. ; Returns:
  347. ;    d0.l =  0 if successful
  348. ;    d0.l = -1 if timeout
  349. ;
  350. ; Trashes:
  351. ;    d0, d1, d2, a2
  352. ;-
  353. sblkacsi:
  354.     move.b    #$88,d1            ; next byte is the opcode
  355.     move.w    d1,XWDL(a1)    ;WDL
  356.  
  357.     move.b    #$8a,d1            ; following bytes are operands
  358.     lea    _cmdblk,a2        ; a2 = address of command block
  359.  
  360.     tst.w    d0            ; is unit # already in command block
  361.     bmi.s    .0            ; if yes, just send command block
  362.                     ; else integrate unit # into cmd blk
  363.     lsl.b    #5,d0            ; shift unit number into place
  364.     or.b    d0,(a2)            ; first command byte = unit # | opcode
  365.                     ; control byte is sent seperately
  366. .0:    subq.w    #2,d2            ; and dbra likes one less 
  367. .1:    swap    d1            ; d1.hw = operand
  368.     move.b    (a2)+,d1        ; d1.lw = tells controller next byte
  369.     swap    d1            ;      is an operand
  370.     move.l    d1,(a1)        ;WDCWDL
  371.     bsr    _qdone
  372.     bmi.s    sbaend            ; if timeout, returns
  373.     dbra    d2,.1            ; else send rest of command block
  374.  
  375.     move.w    d1,XWDL(a1)    ;WDL    ; else get ready to send control byte
  376.     move.b    #0,d1            ; signal sending control byte
  377.     swap    d1            ; d1.hw = operand
  378.     move.b    (a2),d1            ; d1.lw = tells controller it's end
  379.     swap    d1            ;      of command
  380.     move.l    d1,(a1)            ; send it
  381.  
  382.     move.b    #$8a,d1            ; d1 = wdl value
  383.     bsr    _endcmd            ; wait for command completion
  384. sbaend: rts                ; heading home
  385.  
  386.  
  387. ;+
  388. ; setadma() - set the ACSI DMA pointer
  389. ;
  390. ; Passed:
  391. ;    a0.l = buffer address
  392. ;-
  393. setadma:
  394.     move.l    a0,-(sp)        ; move it on stack
  395.     move.b    3(sp),DMALOW        ; set low-byte of address
  396.     move.b    2(sp),DMAMID        ; set mid-byte of address
  397.     move.b    1(sp),DMAHI        ; set high-byte of address
  398.     addq.l    #4,sp            ; clean up stack
  399.     rts
  400.  
  401.  
  402. ;+
  403. ; setacnt() - set the ACSI DMA counter
  404. ;
  405. ; Passed:
  406. ;    d1.l = count (in bytes)
  407. ;    a1.l = pointer to DMA chip
  408. ;-
  409. setacnt:
  410.     cmpi.l    #512,d1            ; transferring more than 512 bytes?
  411.     bhi.s    .0            ; if so, find transfer len in blocks
  412.     move.w    #$01,(a1)    ;WDC    ; else set DMA count to 1 block
  413.     bra.s    sacend
  414. .0:    move.l    d1,-(sp)        ; save transfer length (in bytes)
  415.     lsr.l    #8,d1            ; find transfer length (in blocks)
  416.     lsr.l    #1,d1            ; d1 >>= 9 = transfer len (in blocks)
  417.     move.w    d1,(a1)        ;WDC    ; set DMA count
  418.     move.l    (sp)+,d1        ; restore transfer length (in bytes)
  419. sacend:    rts
  420.  
  421.  
  422.  
  423. .if    !DRIVER                ; not to be included in driver
  424.  
  425. ;+
  426. ; fmtacsi() - format an ACSI unit
  427. ;
  428. ;    d0.w = physical unit number
  429. ;    d2.w = command length (NCMD or LCMD)
  430. ;-
  431.     .globl    _fmtacsi
  432.     .extern    _cmdblk
  433. _fmtacsi:
  434.     st    flock            ; lock FIFO
  435.     bsr    _delay            ; delay if necessary
  436.     movea.l    #WDC,a1            ; a1 = pointer to DMA chip
  437.     andi.w    #7,d0            ; mask off the flags to get unit num
  438.     moveq    #0,d1            ; clear d1
  439.     move.b    #$88,d1            ; next byte is the opcode
  440.     move.w    d1,XWDL(a1)    ;WDL
  441.  
  442.     move.b    #$8a,d1            ; following bytes are operands
  443.     lea    _cmdblk,a2        ; a2 = address of command block
  444.                     ; integrate unit # into cmd blk
  445.     lsl.w    #5,d0            ; shift unit number into place
  446.     or.b    d0,(a2)            ; first command byte = unit # | opcode
  447.                     ; control byte is sent seperately
  448.     subq.w    #2,d2            ; and dbra likes one less 
  449. .0:    swap    d1            ; d1.hw = operand
  450.     move.b    (a2)+,d1        ; d1.lw = tells controller next byte
  451.     swap    d1            ;      is an operand
  452.     move.l    d1,(a1)        ;WDCWDL
  453.     bsr    _qdone
  454.     beq.s    .1            ; if successful, go on
  455.     rts                ; else it timed-out, returns
  456. .1:    dbra    d2,.0            ; send rest of command block
  457.  
  458.     move.w    d1,XWDL(a1)    ;WDL    ; else get ready to send control byte
  459.     move.b    #0,d1            ; signal sending control byte
  460.     swap    d1            ; d1.hw = operand
  461.     move.b    (a2),d1            ; d1.lw = tells controller it's end
  462.     swap    d1            ;      of command
  463.     move.l    d1,(a1)            ; send it
  464.  
  465.     move.b    #$8a,d1            ; d1 = wdl value
  466. .2:    btst    #5,GPIP            ; wait forever for command completion
  467.     bne.s    .2
  468.     bsr    cmdcmp            ; command completed
  469.     bra    _hdone            ; cleanup after IRQ
  470.  
  471.  
  472. ;+
  473. ; stacsi() - start/stop an ACSI unit
  474. ;
  475. ;    d0.w = physical unit number
  476. ;    d2.w = command length (NCMD or LCMD)
  477. ;-
  478.     .globl    _stacsi
  479.     .extern    _cmdblk
  480. _stacsi:
  481.     st    flock            ; lock FIFO
  482.     bsr    _delay            ; delay if necessary
  483.     movea.l    #WDC,a1            ; a1 = pointer to DMA chip
  484.     andi.w    #7,d0            ; mask off the flags to get unit num
  485.     moveq    #0,d1            ; clear d1
  486.     move.b    #$88,d1            ; next byte is the opcode
  487.     move.w    d1,XWDL(a1)    ;WDL
  488.  
  489.     move.b    #$8a,d1            ; following bytes are operands
  490.     lea    _cmdblk,a2        ; a2 = address of command block
  491.                     ; integrate unit # into cmd blk
  492.     lsl.w    #5,d0            ; shift unit number into place
  493.     or.b    d0,(a2)            ; first command byte = unit # | opcode
  494.                     ; control byte is sent seperately
  495.     subq.w    #2,d2            ; and dbra likes one less 
  496. .0:    swap    d1            ; d1.hw = operand
  497.     move.b    (a2)+,d1        ; d1.lw = tells controller next byte
  498.     swap    d1            ;      is an operand
  499.     move.l    d1,(a1)        ;WDCWDL
  500.     bsr    _slwqdone        ; needs a longer short timeout
  501.     beq.s    .1            ; if successful, go on
  502.     rts                ; else it timed-out, returns
  503. .1:    dbra    d2,.0            ; send rest of command block
  504.  
  505.     move.w    d1,XWDL(a1)    ;WDL    ; else get ready to send control byte
  506.     move.b    #0,d1            ; signal sending control byte
  507.     swap    d1            ; d1.hw = operand
  508.     move.b    (a2),d1            ; d1.lw = tells controller it's end
  509.     swap    d1            ;      of command
  510.     move.l    d1,(a1)            ; send it
  511.  
  512.     move.b    #$8a,d1            ; d1 = wdl value
  513.     bsr    _slwendcmd        ; wait for command completion
  514.     bra    _hdone            ; cleanup after IRQ
  515.  
  516. .endif    ;!DRIVER
  517.  
  518.  
  519. ;+
  520. ; Rstdelay()
  521. ;    After talking to the DMA chip in a way that may reset it, 
  522. ; we need a 8 8Mhz clocks (ie. 1 microsec) delay, before we can
  523. ; talk to the chip again.
  524. ;-
  525. rstdelay:
  526.     tst.b    GPIP            ; delay for 1 microsec
  527.     tst.b    GPIP            ; this amounts to 16 16Mhz clocks
  528.     tst.b    GPIP
  529.     tst.b    GPIP
  530.     rts
  531.  
  532.